'''
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Created on Jul 25, 2009

Version: 0.1

@author: bryan
'''
import sys
import vtk
import numpy as np
import pylab
from PyQt4 import QtCore, QtGui
from QVTKRenderWindowInteractor import * 
import JT


class AbstractImageCanvas():
    """
    This class was designed to be used for displaying fixed fluoro images.
    It might be useful to extend it so that it can be used as an image
    backround for DRR images.

    To use: set image filename path (SetFileName) and Render()
    """

    def __init__(self):
        """Initialize class
        """        
        self.ren = JT.vtk.vtkRenderer()
        self.renWin = JT.vtk.vtkRenderWindow() 
        self.renWin.AddRenderer(self.ren)
        self.iren = JT.vtk.vtkRenderWindowInteractor()
        self.iren.SetRenderWindow(self.renWin)
        self.style = JT.vtk.vtkInteractorStyleImage()
        self.iren.SetInteractorStyle(self.style)
        
        # Setup ROI Interaction
        self.roiRen = vtk.vtkRenderer()
        self.renWin.SetNumberOfLayers(2)
        self.ren.SetLayer(0)
        self.roiRen.SetLayer(1)
        self.roi = None
        
        self.bboxPicker = vtk.vtkPropPicker()
        # For ROI interaction
        self.startX = 100
        self.startY = 100
        self.endX = 400
        self.endY = 400
        self.enableROI = False
        self.bboxEnabled = False
        self.moving = False
        
        self.SetCallbacks()
        self.SetupROI()
        
        self._verbose = False


    def SetImage(self,image,flip=False):
        """
        Must pass VTK image data.  This method is called internally when
        the SetFileName function is called.
        """
        self._image = image

        imageSize = []
        imageSize = image.GetDimensions()
        
        #for image to be displayed correctly, it has to be flipped about the X axis
        #Create a VTK Image Flipper
        flipperX = JT.vtk.vtkImageFlip()
        flipperY = JT.vtk.vtkImageFlip()
        flipperX.SetFilteredAxis(0)
        flipperY.SetFilteredAxis(1)
        flipperX.SetInput(image)
        flipperY.SetInput(flipperX.GetOutput())

        # Set size of the render window to be the same as the fixed image
        self.renWin.SetSize((imageSize[0:2]))
        
        mapper = JT.vtk.vtkImageMapper()
        imageActor = JT.vtk.vtkActor2D()
        imageActor.SetMapper(mapper)
        self.ren.AddActor2D(imageActor)
        if flip is True:
            mapper.SetInput(flipperY.GetOutput())
        else:
            mapper.SetInput(image)
        

        # convert the VTK image to a numpy image array to perform some basic calculations
        # numpy support is a fast conversion, so this should be efficient
        # the converted numpy image is stored as a data member of this class for use
        # in other functions.
        self.pyImage = JT.utils.vtk2numpy(image)
        maxPixel = self.pyImage.max()

        mapper.SetColorLevel(maxPixel/2)
        mapper.SetColorWindow(maxPixel)


    def GetImage(self):
        """
        Return the current image (VTK format),
        python (numpy) image can be had by using self._
        """
        if self._image is None:
            print "No image has been set in this instance of image canvas"
        else:
            return self._image
        
    def SetFileName(self,filename):
        """
        Set the filename for the image to be displayed.

        It will be read using the appropriate VTK image file reader
        """
        if self._verbose:
            logging.debug("Image Canvas: opening file: %s" % filename)

        self._fileName =  filename
        
        image = JT.utils.genericImageReader(filename)
        self.SetImage(image)
    
    def Start(self):
        """
        Initiate interaction and render the image.
        """
        self.renWin.Render()
        self.renWin.SetWindowName('Image Canvas')
        self.iren.Start()

    def OverlayImages(self,image1,image2,outputFileName=None):
        """
        overlay two VTK images using contrasting colors (Red and Green) to visualize
        the differences in alignment.

        image1 will be Red, image2 will be Green
        """
        #Set up pipeline components
        lut1=JT.vtk.vtkLookupTable()
        lut2=JT.vtk.vtkLookupTable()

        colors1=JT.vtk.vtkImageMapToColors()
        colors2=JT.vtk.vtkImageMapToColors()

        blender=JT.vtk.vtkImageBlend()

        #First lookup table will map to red
        lut1.SetTableRange(3,65000)
        lut1.SetHueRange(0,0)
        lut1.SetSaturationRange(0.0,1)
        lut1.SetValueRange(1,1)
        lut1.Build()

        #Sec(ond lookup table will map to green
        lut2.SetTableRange(3,65000)
        lut2.SetHueRange(0.33,0.33)
        lut2.SetSaturationRange(0.0,1)
        lut2.SetValueRange(1,1)
        lut2.Build()

        #Make fixed image port 0 (RED) and Moving image port 1 (GREEN)
        colors1.SetInput(image1)
        colors1.SetLookupTable(lut1)

        colors2.SetInput(image2)
        colors2.SetLookupTable(lut2)

        blender.SetInput(0,colors1.GetOutput())
        blender.SetInput(1,colors2.GetOutput())

        #set the opacity of the ports so that both images are visible
        blender.SetOpacity(0,0.5)
        blender.SetOpacity(1,0.5)
        blender.Update()
        
        if outputFileName is None:
            return blender.GetOutput()
        else:
            #Write the image to disk
            writer = JT.vtk.vtkPNGWriter()
            writer.SetInput(blender.GetOutput())
            writer.SetFileName(outputFileName)
            writer.Write()

    def CheckerImages(self,image1,image2,outputFileName=None):
        """
        Combine two images using a checkerboard pattern.  This is useful
        for visualizing the results of a registration.
        image1 and image2 should be VTK images
        outputFileName should be the path to save the result.
        """
        #Set up pipeline components
        #Images must both be grayscale for this function to work
        #So the lut will do convesion
        lut1=JT.vtk.vtkLookupTable()
        lut2=JT.vtk.vtkLookupTable()

        colors1=JT.vtk.vtkImageMapToColors()
        colors2=JT.vtk.vtkImageMapToColors()

        #First lookup table will map to red
        lut1.SetTableRange(0,256)
        lut1.SetHueRange(0,0)
        lut1.SetSaturationRange(0.0,0)
        lut1.SetValueRange(0,1)
        lut1.Build()

        #Sec(ond lookup table will map to green
        lut2.SetTableRange(0,256)
        lut2.SetHueRange(0.0,0.0)
        lut2.SetSaturationRange(0.0,0)
        lut2.SetValueRange(0,1)
        lut2.Build()

        #Make fixed image port 0 (RED) and Moving image port 1 (GREEN)
        colors1.SetInput(image1)
        colors1.SetLookupTable(lut1)

        colors2.SetInput(image2)
        colors2.SetLookupTable(lut2)
        
        checker = JT.vtk.vtkImageCheckerboard()
        checker.SetNumberOfDivisions(8, 8, 1)
        
        checker.SetInput1(colors1.GetOutput())
        checker.SetInput2(colors2.GetOutput())
        checker.Update()
        
        if outputFileName is None:
            return checker.GetOutput()
        else:
            writer = JT.vtk.vtkPNGWriter()
            writer.SetInput(checker.GetOutput())
            writer.SetFileName(outputFileName)
            writer.Write()

    def GetGrayscale(self,image1):
        """
        Given an unsigned uchar image, this filter will convert a rgb image
        to grayscale (using vtkImageMapToColors).
        """
        #So the lut will do convesion
        lut1=JT.vtk.vtkLookupTable()

        colors1=JT.vtk.vtkImageMapToColors()

        #First lookup table will map to red
        lut1.SetTableRange(0,256)
        lut1.SetHueRange(0,0)
        lut1.SetSaturationRange(0.0,0)
        lut1.SetValueRange(0,1)
        lut1.Build()

        #Make fixed image port 0 (RED) and Moving image port 1 (GREEN)
        colors1.SetInput(image1)
        colors1.SetLookupTable(lut1)
        colors1.Update()
        
        return colors1.GetOutput()
    
    def SetupROI(self):
        """
        call after image is added???
        """
        self.pts = vtk.vtkPoints()
        self.pts.SetNumberOfPoints(4)
        lines = vtk.vtkCellArray()
        lines.InsertNextCell(5)
        lines.InsertCellPoint(0)
        lines.InsertCellPoint(1)
        lines.InsertCellPoint(2)
        lines.InsertCellPoint(3)
        lines.InsertCellPoint(0)
        pd = vtk.vtkPolyData()
        pd.SetPoints(self.pts)
        pd.SetLines(lines)
        
        # Create a handle to move the ROI
        gs = vtk.vtkGlyphSource2D()
        gs.SetGlyphTypeToSquare()
        gs.SetColor(1, 0, 0)
        gs.SetScale(10)
        gs.FilledOn()
        gs.CrossOn()
        
        glyphMapper = vtk.vtkPolyDataMapper2D()
        glyphMapper.SetInput(gs.GetOutput())
        
        self.glyphActor = vtk.vtkActor2D()
        self.glyphActor.SetMapper(glyphMapper)
        
        bboxMapper = vtk.vtkPolyDataMapper2D()
        bboxMapper.SetInput(pd)
        self.bboxActor = vtk.vtkActor2D()
        self.bboxActor.SetMapper(bboxMapper)
        self.bboxActor.GetProperty().SetColor(1, 0, 0)
        self.bboxActor.PickableOff()
        self.glyphActor.VisibilityOff()
        self.roiRen.AddViewProp(self.bboxActor)
        self.roiRen.AddViewProp(self.glyphActor)
        #self.renWin.Render()
    
    def SetCallbacks(self):
        #self.iren.RemoveAllObservers()
        self.style.AddObserver("LeftButtonPressEvent", self.OnLeftDown)
        self.style.AddObserver("LeftButtonReleaseEvent", self.OnLeftUp)
        self.style.AddObserver("MouseMoveEvent", self.OnMouseMove)
        self.style.AddObserver("CharEvent", self.OnChar)
    
    def OnChar(self,obj,event):
        # key is necessary for arrows
        keynum = self.iren._key
        # keycode will give the character that was pushed
        keysym = self.iren._keycode
        
        if keysym == 'i':
            if self.enableROI:
                self.enableROI = False
            else:
                self.enableROI = True
        elif keysym == 'r':
            visible = self.bboxActor.GetVisibility()
            #print visible
            if visible:
                self.bboxActor.VisibilityOff()
                self.glyphActor.VisibilityOff()
                self.renWin.Render()
            else:
                self.glyphActor.VisibilityOn()
                self.bboxActor.VisibilityOn()
                self.renWin.Render()
#    
    def OnLeftDown(self,obj,event):
        xy = self.iren.GetEventPosition()
        if self.enableROI:
            if self.bboxPicker.PickProp(xy[0], xy[1], self.roiRen):
                # if the bbox is picked, then move it, don't redraw it
                self.moving = True
                print "Moving"
                self.ROIStartMove()
            else:
                print "Drawing"
                self.moving = False
                self.ROIStartDraw()
                
    def OnLeftUp(self,obj,event):
        if self.moving:
            self.ROIEndMove()
        else:
            self.ROIEndDraw()
        
    def OnMouseMove(self,obj,event):
        if self.moving:
            self.ROIMouseMove()
        else:
            self.ROIMouseDraw()
        
    def ROIStartDraw(self):
        if self.enableROI:
            xy = self.iren.GetEventPosition()
            X, Y = xy
            self.startX, self.startY = xy
            self.pts.SetPoint(0, X, Y, 0)
            self.pts.SetPoint(1, X, Y, 0)
            self.pts.SetPoint(2, X, Y, 0)
            self.pts.SetPoint(3, X, Y, 0)
            self.bboxEnabled = 1
            self.bboxActor.VisibilityOn()
            self.renWin.Render()
            
    def ROIEndDraw(self):
        if self.enableROI:
            xy = self.iren.GetEventPosition()
            self.endX, self.endY = xy
            self.PlaceGlyph()
            self.bboxEnabled = 0
            self.bboxActor.VisibilityOn()
            self.renWin.Render()
            self.saveROI()

    def ROIMouseDraw(self):
        if self.enableROI:
            if self.bboxEnabled:
                self.glyphActor.VisibilityOff()
                xy = self.iren.GetEventPosition()
                x, y = xy
                X, Y = [self.startX, self.startY]
                self.endX, self.endY = xy
                self.pts.SetPoint(1, x, Y, 0)
                self.pts.SetPoint(2, x, y, 0)
                self.pts.SetPoint(3, X, y, 0)
                self.renWin.Render() 
    
    def ROIStartMove(self):
        if self.enableROI:
            self.lastX = self.glyphX
            self.lastY = self.glyphY
            self.bboxEnabled = True
    
    def ROIEndMove(self):
        if self.enableROI:
            self.bboxEnabled = False
            self.moving = False
            self.bboxActor.VisibilityOn()
            self.renWin.Render()
            self.startX = self.pts.GetPoint(0)[0]
            self.startY = self.pts.GetPoint(0)[1]
            self.endX = self.pts.GetPoint(2)[0]
            self.endY = self.pts.GetPoint(2)[1]
            self.saveROI()
    
    def ROIMouseMove(self):
        if self.enableROI:
            if self.bboxEnabled:
                self.glyphActor.VisibilityOn()
                xy = self.iren.GetEventPosition()
                x, y = xy
                diffX, diffY = [x-self.lastX, y-self.lastY]
                self.lastX = x
                self.lastY = y
                self.SetROI((self.roi[0]+diffY,self.roi[1]+diffX,
                             self.roi[2]+diffY,self.roi[3]+diffX))
                self.PlaceGlyph()
                self.renWin.Render() 
    
    def PlaceGlyph(self):
        """
        place glyph at the upper left corner of the ROI box
        """
        pts=[]
        for i in range(4):
            pts.append(self.pts.GetPoint(i)[0:2])
        pts = np.asarray(pts)
        Xmin = pts[:,0].min()
        Ymin = pts[:,1].min()
        Xmax = pts[:,0].max()
        Ymax = pts[:,1].max()
        #print "Xmin etc", Xmin,Ymin,Xmax,Ymax
        self.glyphX = Xmin
        self.glyphY = Ymin
        self.glyphActor.SetPosition(Xmin,Ymin)
        if ((Xmax-Xmin)<1) or ((Ymax-Ymin)<1):
            #No ROI specified
            self.glyphActor.VisibilityOff()
        else:
            self.glyphActor.VisibilityOn()
    
    def SetROI(self,roi):
        """
        Allow an ROI to be specified and displayed.
        """
        self.pts.SetPoint(0, roi[1], roi[0], 0)
        self.pts.SetPoint(1, roi[3], roi[0], 0)
        self.pts.SetPoint(2, roi[3], roi[2], 0)
        self.pts.SetPoint(3, roi[1], roi[2], 0)
        self.PlaceGlyph() 
        self.roi = roi
        self.bboxActor.VisibilityOn()   
        self.renWin.Render()  

    def saveROI(self):
        #print self.startX,self.startY,self.endX,self.endY
        #print X,Y,x,y
        image_size = self.renWin.GetSize()
#        X,Y = [image_size[0]-self.startX,image_size[1]-self.startY]
#        x,y = [image_size[0]-self.endX,image_size[1]-self.endY]
        X,Y = [self.startX,self.startY]
        x,y = [self.endX,self.endY]
        upperLeft = [np.min([Y,y]),np.min([X,x])]
        lowerRight = [np.max([Y,y]),np.max([X,x]),]
        try:
            # Changed ROI format from nested list of two pairs to one list of 
            # four integers. This will make the roi much easier to parse 
            # when stored as a string (in xml)
            self.roi = [int(upperLeft[0]),int(upperLeft[1]),
                        int(lowerRight[0]),int(lowerRight[1])]
        except AttributeError:
            print "ROI not saved, no interactor"
        print "ROI(x and y reversed): (%i, %i, %i, %i)" % \
            (upperLeft[0],upperLeft[1],
             lowerRight[1],lowerRight[0])

    

class ImageCanvas(AbstractImageCanvas):
    """
    Implementation of AbstractImageCanvas
    """
    pass
    

class QTImageCanvas(AbstractImageCanvas):
    """
    A modified version of ImageCanvas that is able to work with QT GUI 
    """
    def __init__(self,parent_obj):
        """
        Constructor.  Pass a parent object for the QT render window
        """
        AbstractImageCanvas.__init__(self)
        self.iren = QVTKRenderWindowInteractor(parent_obj)
        self.renWin = self.iren.GetRenderWindow()
        self.renWin.AddRenderer(self.ren)
                
        self.renWin.AddRenderer(self.roiRen)
        self.style = vtk.vtkInteractorStyleImage()
        self.iren.SetInteractorStyle(self.style)
        
        # Setup ROI Interaction
        # Setup ROI Interaction
        #self.roiRen = vtk.vtkRenderer()
        self.renWin.SetNumberOfLayers(2)
        #self.ren.SetLayer(0)
        #self.roiRen.SetLayer(1)
        
        # Create a signal for when the roi has been updated
        self.roi_changed = QtCore.SIGNAL("roi_changed(PyQt_PyObject)")
        
        self.SetCallbacks()
        self.SetupROI()
        
        self._verbose = False
        

    def SetImage(self,image,flip=False):
        """
        Must pass VTK image data.  This method is called internally when
        the SetFileName function is called.
        """
        self._image = image

        self.imageSize = []
        self.imageSize = image.GetDimensions()
        
        #for image to be displayed correctly, it has to be flipped about the X axis
        #Create a VTK Image Flipper
        flipperX = JT.vtk.vtkImageFlip()
        flipperY = JT.vtk.vtkImageFlip()
        flipperX.SetFilteredAxis(0)
        flipperY.SetFilteredAxis(1)
        flipperX.SetInput(image)
        flipperY.SetInput(flipperX.GetOutput())

        # Set size of the render window to be the same as the fixed image
        self.renWin.SetSize((self.imageSize[0:2]))
        
        self.mapper = JT.vtk.vtkImageMapper()
        imageActor = JT.vtk.vtkActor2D()
        imageActor.SetMapper(self.mapper)
        self.ren.AddActor2D(imageActor)
        if flip is True:
            self.mapper.SetInput(flipperY.GetOutput())
        else:
            self.mapper.SetInput(image)
        
        # convert the VTK image to a numpy image array to perform some basic calculations
        # numpy support is a fast conversion, so this should be efficient
        # the converted numpy image is stored as a data member of this class for use
        # in other functions.
        self.pyImage = JT.utils.vtk2numpy(image)
        maxPixel = self.pyImage.max()

        self.mapper.SetColorLevel(maxPixel/2)
        self.mapper.SetColorWindow(maxPixel)
    
    def SetColorLevel(self,value):
        """
        """
        self.mapper.SetColorLevel(value)
        self.iren.emit(QtCore.SIGNAL("color_level_changed(PyQt_PyObject)"), value)
        self.renWin.Render()
        
    def SetWindowLevel(self,value):
        """
        """
        self.mapper.SetColorWindow(value)
        self.iren.emit(QtCore.SIGNAL("window_level_changed(PyQt_PyObject)"), value)
        self.renWin.Render()

    def GetImage(self):
        """
        Return the current image (VTK format),
        python (numpy) image can be had by using self._
        """
        if self._image is None:
            print "No image has been set in this instance of image canvas"
        else:
            return self._image
        
    def SetFileName(self,filename):
        """
        Set the filename for the image to be displayed.

        It will be read using the appropriate VTK image file reader
        """
        if self._verbose:
            logging.debug("Image Canvas: opening file: %s" % filename)

        self._fileName =  filename
        
        image = JT.utils.genericImageReader(filename)
        self.SetImage(image)
    
    def saveROI(self):
        """
        had to override this method to add a QT signal 
        """
        X,Y = [self.startX,self.startY]
        x,y = [self.endX,self.endY]
        upperLeft = [np.min([Y,y]),np.min([X,x])]
        lowerRight = [np.max([Y,y]),np.max([X,x]),]
        self.roi = [int(upperLeft[0]),int(upperLeft[1]),
                         int(lowerRight[0]),int(lowerRight[1])]
        # Emit a signal to let everyone know that a new roi was selected
        self.iren.emit(QtCore.SIGNAL("roi_changed(PyQt_PyObject)"), self.roi)
    


class QTWipeImageCanvas(AbstractImageCanvas):
    """
    A modified version of ImageCanvas that is able to work with QT GUI 
    """
    def __init__(self,parent_obj):
        """
        Constructor.  Pass a parent object for the QT render window
        """
        AbstractImageCanvas.__init__(self)
        self._verbose = False
        self.iren = QVTKRenderWindowInteractor(parent_obj)
        self.renWin = self.iren.GetRenderWindow()
        self.renWin.AddRenderer(self.ren)
        self.style = vtk.vtkInteractorStyleImage()
        self.iren.SetInteractorStyle(self.style)

        self.wipe = JT.vtk.vtkImageRectilinearWipe()
        self.wipe.SetWipeToQuad()
        self.wipeActor = JT.vtk.vtkImageActor()
        self.wipeActor.SetInput(self.wipe.GetOutput())
        self.wipeWidget = JT.vtk.vtkRectilinearWipeWidget()
        self.wipeWidget.SetInteractor(self.renWin.GetInteractor())
        wipeWidgetRep = JT.vtk.vtkRectilinearWipeRepresentation()
        wipeWidgetRep.SetRectilinearWipe(self.wipe)
        wipeWidgetRep.SetImageActor(self.wipeActor)
        wipeWidgetRep.GetProperty().SetLineWidth(2.0)
        wipeWidgetRep.GetProperty().SetOpacity(0.5)
        self.wipeWidget.SetRepresentation(wipeWidgetRep)
        self.ren.AddActor(self.wipeActor)
        self.wipe.SetPosition(250,250)
    
    def GetStyle(self):
        return self.style
        
    def SetImage1(self,image,flip=False):
        # need to flip VTK images
        flipperX = JT.vtk.vtkImageFlip()
        flipperY = JT.vtk.vtkImageFlip()
        flipperX.SetFilteredAxis(0)
        flipperY.SetFilteredAxis(1)
        flipperX.SetInput(image)
        flipperY.SetInput(flipperX.GetOutput())
        flipperY.Update()
        
        # Make sure iamge is uchar
        caster = JT.vtk.vtkImageShiftScale()
        if flip is True:
            caster.SetInput(flipperY.GetOutput())
        else:
            caster.SetInput(image)
        caster.SetOutputScalarTypeToUnsignedChar()
        caster.SetScale(255.0/image.GetScalarTypeMax())
        
        # convert to grayscale
        image_gray = self.GetGrayscale(caster.GetOutput())
        image_gray.Update()
        self.wipe.SetInput1(image_gray)
        size = image.GetDimensions()
        
    
    def SetImage2(self,image,flip=False):
        # need to flip VTK images
        flipperX = JT.vtk.vtkImageFlip()
        flipperY = JT.vtk.vtkImageFlip()
        flipperX.SetFilteredAxis(0)
        flipperY.SetFilteredAxis(1)
        flipperX.SetInput(image)
        flipperY.SetInput(flipperX.GetOutput())
        flipperY.Update()
        # Make sure iamge is uchar
        caster = JT.vtk.vtkImageShiftScale()
        if flip is True:
            caster.SetInput(flipperY.GetOutput())
        else:
            caster.SetInput(image)
        caster.SetOutputScalarTypeToUnsignedChar()
        caster.SetScale(255.0/image.GetScalarTypeMax())
        # convert to grayscale
        image_gray = self.GetGrayscale(caster.GetOutput())
        image_gray.Update()
        self.wipe.SetInput2(image_gray)
        self.wipe.Update()

        
def scriptWipe():
    # Setup Rendering components
    renWin = JT.vtk.vtkRenderWindow()
    iren = JT.vtk.vtkRenderWindowInteractor()
    ren = JT.vtk.vtkRenderer()
    style = JT.vtk.vtkInteractorStyleImage()
    iren.SetInteractorStyle(style)
    
    iren.SetRenderWindow(renWin)
    renWin.AddRenderer(ren)
    
    filename1 = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim080-LAT.mhd'
    filename2 = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim042-AP.mhd'
    image1 = JT.utils.genericImageReader(filename1)
    image2 = JT.utils.genericImageReader(filename2)
    
    #make sure images are unsigned char first 
    caster1 = JT.vtk.vtkImageShiftScale()
    caster1.SetInput(image1)
    caster1.SetOutputScalarTypeToUnsignedChar()
    caster1.SetScale(250.0/image1.GetScalarTypeMax())
    caster2 = JT.vtk.vtkImageShiftScale()
    caster2.SetInput(image2)
    caster2.SetOutputScalarTypeToUnsignedChar()
    caster2.SetScale(255.0/image2.GetScalarTypeMax())
    
    wipe = JT.vtk.vtkImageRectilinearWipe()
    wipe.SetInput1(caster1.GetOutput())
    wipe.SetInput2(caster2.GetOutput())
    wipe.SetPosition(256, 256)
    wipe.SetWipeToQuad()
    wipeActor = JT.vtk.vtkImageActor()
    wipeActor.SetInput(wipe.GetOutput())
    wipeWidget = JT.vtk.vtkRectilinearWipeWidget()
    wipeWidget.SetInteractor(iren)
    wipeWidgetRep = JT.vtk.vtkRectilinearWipeRepresentation()
    wipeWidgetRep.SetRectilinearWipe(wipe)
    wipeWidgetRep.SetImageActor(wipeActor)
    wipeWidgetRep.GetProperty().SetLineWidth(2.0)
    wipeWidgetRep.GetProperty().SetOpacity(0.75)
    wipeWidget.SetRepresentation(wipeWidgetRep)
    
    ren.AddActor2D(wipeActor)
    renWin.SetSize(512,512)
    iren.Initialize()
    renWin.Render()
    iren.Start()

    
def show_cone():
    """
    Return a vtk cone actor with resolution
    """
    QtGui.QApplication.setStyle('cleanlooks')
    app = QtGui.QApplication(sys.argv) 
    mainWindow = QtGui.QMainWindow()
    frameWidget = QtGui.QFrame(mainWindow)
    mainWindow.setCentralWidget(frameWidget)
    mainWindow.setFixedSize(400,400)
    
    canvas = QTImageCanvas(frameWidget) 
    
    cone = vtk.vtkConeSource()
    cone.SetResolution(10)
    
    coneMapper = vtk.vtkPolyDataMapper() 
    coneMapper.SetInput(cone.GetOutput()) 
    coneMapper.SetScalarRange(0,1)
    
    coneActor = vtk.vtkActor() 
    coneActor.SetMapper(coneMapper)    
    renderer = vtk.vtkRenderer() 
    renderer.AddActor(coneActor)
    
    renWin = canvas.iren.GetRenderWindow() 
    renWin.AddRenderer(renderer)
    
    canvas.iren.Initialize()
    
    mainWindow.show() 
    app.exec_()

def test_roi():
    """
    Return a vtk cone actor with resolution
    """
    QtGui.QApplication.setStyle('cleanlooks')
    app = QtGui.QApplication(sys.argv) 
    mainWindow = QtGui.QMainWindow()
    frameWidget = QtGui.QFrame(mainWindow)

    mainWindow.setCentralWidget(frameWidget)
    canvas = QTImageCanvas(frameWidget)
    
    def roi_callback(roi):
        print "Hello: %s" % str(roi)
        canvas.SetROI(roi)
    
    # Test roi signal
    mainWindow.connect(canvas.iren,QtCore.SIGNAL("roi_changed(PyQt_PyObject)"),
                       roi_callback)
    
    mainWindow.setFixedSize(512,512)
    canvas.iren.setFixedSize(512,512)

    #canvas.iren.setFixedSize(512,512)
    filename = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim080-LAT.mhd'
    
    #canvas.ren.AddActor2D(canvas.iren.GetInteractorStyle().bboxActor)
    canvas.SetFileName(filename)
    canvas.iren.Initialize()
    canvas.renWin.Render()
    canvas.iren.Start()
    
    mainWindow.show() 
    app.exec_()
    
    roi = canvas.roi
    roi = np.asarray(roi,'int')
    print "Saved ROI: %s" % str(roi)
    roi = np.asarray(roi,'int')
    print roi[0],roi[1],roi[2],roi[3]
    cropimage = canvas.pyImage[roi[0]:roi[2], roi[1]:roi[3]]
    print cropimage.shape
    pylab.ion()
    pylab.imshow(cropimage,origin='lower')
    pylab.bone()
    
    pylab.show()
    #done = raw_input("Press Enter to quit:")

def test_style():
    """
    Return a vtk cone actor with resolution
    """
    ren = vtk.vtkRenderer()
    ren.SetBackground(1,1,1)
    renWin = vtk.vtkRenderWindow() 
    renWin.AddRenderer(ren)
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)
    style = vtk.vtkInteractorStyleTrackballCamera()
    iren.SetInteractorStyle(style)

    #filename = r'C:\Users\bryan\phd\dissertation\Figures/ucharim080-LAT.png'
    filename = r'C:\Users\bryan\phd\dissertation\Figures/DRR_RayCast.png'
    
    image = JT.utils.genericImageReader(filename)
    
    mapper = vtk.vtkImageMapper()
    imageActor = vtk.vtkImageActor()
    imageActor.SetInput(image)
    ren.AddActor(imageActor)
    mapper.SetInput(image)
    
    pyImage = JT.utils.vtk2numpy(image)
    maxPixel = pyImage.max()

    mapper.SetColorLevel(maxPixel/2)
    mapper.SetColorWindow(maxPixel)
    
    iren.Initialize()
    renWin.Render()
    iren.Start()
    

    
def test_wipe():
    """
    Create an image viewer with a wipe widget
    """
    QtGui.QApplication.setStyle('cleanlooks')
    app = QtGui.QApplication(sys.argv) 
    mainWindow = QtGui.QMainWindow()
    
    frameWidget = QtGui.QFrame(mainWindow)

    mainWindow.setCentralWidget(frameWidget)
    canvas = QTWipeImageCanvas(frameWidget) 
    
    filename1 = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim080-LAT.mhd'
    filename2 = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim042-AP.mhd'
    image1 = JT.utils.genericImageReader(filename1)
    image2 = JT.utils.genericImageReader(filename2)

    mainWindow.setFixedSize(512,512)
    canvas.iren.setFixedSize(512,512)
    
    canvas.SetImage1(image1)
    canvas.SetImage2(image2)
    
    #wipeActor = canvas.setupWipe(image1, image2)
    #canvas.setupROISelection()
    #canvas.imageRen.AddActor2D(wipeActor)
    
    canvas.iren.Initialize()
    canvas.renWin.Render()
    canvas.iren.Start()
    
    mainWindow.show() 
    app.exec_()

def test_color():
    """
    Create an image viewer with a wipe widget
    """
    QtGui.QApplication.setStyle('cleanlooks')
    app = QtGui.QApplication(sys.argv) 
    mainWindow = QtGui.QMainWindow()
    
    frameWidget = QtGui.QFrame(mainWindow)

    mainWindow.setCentralWidget(frameWidget)
    canvas = QTImageCanvas(frameWidget) 
    
    filename1 = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim080-LAT.mhd'
    filename2 = 'C:/Users/bryan/bryan-code/2D3D/vert1/fluoro/ushortim042-AP.mhd'
    image1 = JT.utils.genericImageReader(filename1)
    image2 = JT.utils.genericImageReader(filename2)

    mainWindow.setFixedSize(512,512)
    canvas.iren.setFixedSize(512,512)
    
    colorImage = canvas.OverlayImages(image1,image2)
    canvas.SetImage(colorImage)
    
    canvas.iren.Initialize()
    canvas.renWin.Render()
    canvas.iren.Start()
    
    mainWindow.show() 
    app.exec_()


if __name__ == '__main__':
    test_style()